(function(){
	var Collections = require('./Collections'),
        ObjectUtils = require('./ObjectUtils'),
        StringUtils = require('./StringUtils'),
        chain       = require('./CommandChain'),
        AutoCompleteResponse = require('./AutoCompleteResponse').ctor;
	
	var Map     = Collections.Map,
	    List    = Collections.List,
	    iterate = Collections.iterate,
	    filter  = Collections.filter;
	
	var merge   = ObjectUtils.merge,
	    propertyAccessor = ObjectUtils.propertyAccessor;
	
	var toHTML  = StringUtils.toHTML,
	    format  = StringUtils.format;
	
	namespace('org.jsmud.entity');
	
	org.jsmud.entity.User = function(userService, data){
		this.userService = userService;
		this.data = data;
		this.carryables = [];
		this.wearables  = [];
	};
	org.jsmud.entity.User.prototype = {
		commands : {
			create : {
				onExecute : function(){
					var data = {};
					var user = new org.jsmud.entity.User(this.userService, data);
					this.session.setUser(user);
				},
				onAutoComplete : function(){
					
				}
			},
			save : {
				onExecute : function(){
					this.owner.save();
				}
			},
//			describe : {
//				onExecute : function(){
//					var user = this.owner;
//					var html  = toHTML(user.data);
//					this.onResponse(html);
//				}
//			},
			put : {
				onExecute : function(item){
					var _container;
					var _item;

					var room = this.session.getRoom();
					var user = this.session.getUser();

					var container = null;
					if( !arguments || arguments.length === 0 ) _item = user.carryables[0];
					if( arguments && arguments.length <=  1 ) _container = room;
					if( arguments && arguments[1] == 'in' ) container = arguments[2];
					
					var onResponse = this.onResponse;
					var itemService = this.session.itemService;
					var _chain = chain.create();
					var update = function(){
						if(!_item){
							onResponse(format("Item '${item}' not found.", {item:item}));
						}else if(!_container){
							onResponse(format("Container '${container}' not found.", {container:container}));
						}else{
							_item.data.container.collectionName = _container.type;
							_item.data.container._id = _container.getId();
							_item.data.container.position = null;
							_item.save(function(){
								user.refresh();
								_container.refresh();
							});
						}
					}
					var findContainer = function(){
						if( _container ){
							_chain.proceed();
						}else{
							var example = {$or:
								[{name:container, 'container.collectionName':'user', 'container.position':'carryables', 'container._id':user.getId()}
								,{name:container, 'container.collectionName':'user', 'container.position':'wearables', 'container._id':user.getId()}
								,{name:container, 'container.collectionName':'room', 'container._id':room.getId()}
							]};
							itemService.findByExample(example, function(results){
								if( results.length != 1 ){
									onResponse('Container not found : ' + container);
									return;
								}
								_container = results[0];
								console.log("Container:"+_container);
								_chain.proceed();
							});
						}
					};
					var findItem = function(){
						if(_item){
							_chain.proceed();
						}else{
							var found = filter(user.carryables, item, propertyAccessor('data.name'));
							if( found.length != 1){
								onResponse('Item not found : ' + item);
							}else{
								_item = found[0];
								_chain.proceed();
							}
						}
					};
					
					_chain.add({method:findContainer, scope:this, arguments:[]})
						  .add({method:findItem, scope:this, arguments:[]})
						  .add({method:update, scope:this, arguments:[]})
						  .execute();
				}
			},
			drop : {
				onExecute : function(item){
					var onResponse = this.onResponse;
					var user = this.owner;
					var room = this.session.getRoom();
					
					var example = {container:{collectionName:'user', position:'carryable', _id:user.getId()}}
					this.session.itemService.findByExample(example, function(results){
						var _item;
						iterate(results, function(result){
							if( result.data.name == item ){
								_item = result;
							}
						});
						if(_item){
							_item.data.container.collectionName = 'room';
							_item.data.container._id = room.getId();
							_item.data.container.position = null;
							_item.save();
						}
					});
				},
				onAutoComplete : function(value){
					var onResponse = this.onResponse;
					var user = this.owner;
					var example = {container:{collectionName:'user', position:'carryable', _id:user.getId()}}
					this.session.itemService.findByExample(example, function(results){
						onResponse(new AutoCompleteResponse(value, [{values:results, _toString:propertyAccessor('data.name')}]));
					});
				}
			},
			inventory : {
				onExecute : function(){
					var user = this.owner;
					this.onResponse(user.wearables);
				}
			},
			glance : {
				onExecute : function(){
					var user = this.owner;
					this.onResponse(user.carryables);
				}
			}
		},
		getCommands : function(onResponse){
			var response = {};
			Map.putAll(response, this.commands, merge({owner:this}).mapEntry)
			onResponse(response);
		},
		save : function(){
			this.userService.save(this.data);
		},
		setRoomId : function(roomId){
			this.data.roomId = roomId;
		},
		getRoomId : function(){
			return this.data.roomId;
		},
		getId : function(){
			return this.data._id;
		},
		refresh : function(onDone){
			this.userService.updateAssociations(this, onDone);
		}
	};
})()